package cn.tonyandmoney.baidu

import android.content.Context
import cn.tonyandmoney.baidu.asr.adapter.RecogEventAdapter
import cn.tonyandmoney.baidu.asr.config.IRecogParams
import cn.tonyandmoney.baidu.asr.controller.Recognizer
import cn.tonyandmoney.baidu.asr.event.EventRecogCallback
import cn.tonyandmoney.baidu.bus.SpeechBus
import cn.tonyandmoney.baidu.consumers.RxConsumer
import cn.tonyandmoney.baidu.event.SpeechEvent
import cn.tonyandmoney.baidu.tts.Speaker
import cn.tonyandmoney.baidu.tts.event.SpeakEvent
import com.google.gson.Gson
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.functions.Consumer
import io.reactivex.schedulers.Schedulers
import org.jetbrains.anko.AnkoLogger
import org.jetbrains.anko.info

class SpeechImpl(context: Context,
                 consumer: Consumer<SpeechEvent>,
                 val params: IRecogParams) : EventRecogCallback(), ISpeech, AnkoLogger, Consumer<SpeakEvent> {

    private val TAG = "SpeechImpl"
    private lateinit var mSpeaker: Speaker
    private lateinit var mRecognizer: Recognizer
    override var isRecognizing: Boolean = false
    private var isInitOk = false
    private val isAutoStop = Object()

    init {
        Observable.create<SpeechEvent> {
            mRecognizer = Recognizer(context.applicationContext)
            mRecognizer.registerCallback(RecogEventAdapter(this))
            val offlineMap = params.fetchOfflineParams()
            if (offlineMap != null) {
                mRecognizer.loadOfflineEngine(Gson().toJson(offlineMap))
            }
            mSpeaker = Speaker()
            mSpeaker.init(context.applicationContext)
            isInitOk = true
            SpeechBus.register(this)
            it.onNext(SpeechEvent(SpeechEvent.Companion.State.START, "启动执行完毕。"))
            it.onComplete()
        }.subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(RxConsumer(consumer))
    }


    override fun getSpeaker(): Speaker {
        return mSpeaker
    }

    /**
     * 接收的是语音播放的事件
     * 当语音提示的时候，需要停止语音识别的录音功能
     * 否则会出现错误
     */
    override fun accept(t: SpeakEvent) {
        if (t.code == SpeakEvent.CODE_START) {
            waitSpeakEnd()
            stop()
        } else if (t.code == SpeakEvent.CODE_FINISH || t.code == SpeakEvent.CODE_ERROR) {
            synchronized(isAutoStop) {
                isAutoStop.notifyAll()
            }
        } else if (t.code == SpeakEvent.CODE_SPEAK) {
            speak(t.message, t.id)
        }
    }

    /**
     * 给一个线程锁，让它等待语音播报完成
     * 然后重启语音识别
     */
    private fun waitSpeakEnd() {
        Schedulers.newThread().scheduleDirect {
            synchronized(isAutoStop) {
                isAutoStop.wait()
                start()
            }
        }
    }

    override fun start() {
        if (!isInitOk) {
            info("引擎初始化未成功。")
            return
        }
        synchronized(isRecognizing) {
            isRecognizing = true
            val paramsJson = Gson().toJson(params.fetchParams())
            mRecognizer.start(paramsJson)
        }
    }

    override fun stop() {
        if (!isInitOk) {
            info("引擎初始化未成功。")
            return
        }
        synchronized(isRecognizing) {
            isRecognizing = false
            mRecognizer.stop()
            mRecognizer.cancel()
        }
    }

    override fun destroy() {
        if (isRecognizing) {
            mRecognizer.cancel()
            mRecognizer.stop()
        }
        mRecognizer.release()
        mSpeaker.release()
    }

    override fun speak(content: String, id: String?) {
        if (!isInitOk) {
            info("引擎初始化未成功。")
            return
        }
        mSpeaker.speak(content, id)
    }
}